DOM 中的 attribute 和 property 的区别
看到了这样的面试题,但是给出的答案太简短了。还有很多不太懂的地方。
定义
当浏览器加载页面时,会解析 HTML 文本,并从中生成 DOM 对象。对于元素节点,大多数标准的 HTML 属性(attribute)会自动成为 DOM 对象的属性(property)。
例如,如果标签是 <div id"div1"><div>
,那么 DOM 对象有 div.id"div1"
,在这里 attribute 和 property 具有1:1的映射(同步)的关系,这一点在后面会讨论。
但并不是所有的 attribute 和 property 都有1:1的映射(同步)的关系
DOM property(属性)
property 属性属于 DOM 对象, DOM 实质就是 javascript 中的对象。1
2
3window.document.myform.text1
// 等同于这样写
document.myform.text1
DOM 的属性和方法与常规 JavaScript 对象的行为一样,因此,我们可以在 js 中操作普通对象一样获取、设置 DOM 对象的属性。
- property 属性可以是任意数据类型,
- property 对大小写敏感。
所以,
自定义的 property 不会出现在 html 代码中,只存在 js 中,
这句话也就不难理解了。
HTML Attribute(特性)
attribute 特性由 HTML 定义,所有出现在 HTML 标签内的描述节点都是 attribute 特性。
在 HTML 语言中,标签可能有 attribute 属性。 当浏览器读取 HTML 文本并为标签创建 DOM 对象时,它会识别标准属性并从中创建 DOM 属性。
因此,当一个元素具有 id 或其他标准属性(attribute)时,相应的属性(property)就会被创建。 但是,如果 attribute 是非标准的,则不会发生这种情况。
1 | <body id="test" something="non-standard"> |
注意,一个元素的标准属性对另一个元素来说是未知的。 例如,”type”是输入的标准(HTMLInputElement) ,而不是 body (HTMLBodyElement)。 标准属性在相应元素类的规范中被描述。
1 | <body id="test" something="non-standard"> |
因此,如果一个属性是非标准的,那么它就不会有 DOM-property。 有没有方法可以访问这些属性?
- elem.hasAttribute(name) 检测该 attribute 是否存在
- elem.getAttribute(name) 获取该 attribute 的值
- elem.setAttribute(name, value) 设置该 attribute 的值
- elem.removeAttribute(name) – 移除该 attribute
- attribute 特性的类型总是字符串类型,
- 对大小写不敏感。
标准(非自定义) attribute 特性 与 property有1:1的映射(同步)关系,比如:id, class, title, style等
在大多数情况下,当 attribute
(或 property
)发生更改,相应的property
(或 attribute
)也会自动同步更新,反之亦然。1
2
3
4
5
6
7
8
9
10
11
12
13<input>
<script>
let input = document.querySelector('input');
// attribute => property
input.setAttribute('id', 'id');
alert(input.id); // id (updated)
// property => attribute
input.id = 'newId';
alert(input.getAttribute('id')); // newId (updated)
</script>
例子2:1
2
3
4
5
6<div id="test" class="button"></div>
var div = document.getElementById('test');
div.className = 'red-input';
div.getAttribute('class'); // return string: "red-input"
div.setAttribute('class','green-input');
div.className; // return string: "green-input"
注意:当我们通过 property
属性进行设置或获取 class
时,我们需要使用” className
“,因为在js中 class
是关键字。
但有例外的情况,比如 value
只是从 attribute
-> property
,单向同步。1
2
3
4
5
6
7
8
9
10
11
12
13<input>
<script>
let input = document.querySelector('input');
// attribute => property
input.setAttribute('value', 'text');
alert(input.value); // text
// NOT property => attribute
input.value = 'newValue';
alert(input.getAttribute('value')); // text (not updated!)
</script>
听说?这里还不是很了解。getAttribute 方法有一个潜规则,部分属性(input的value和checked)通过getAttribut取到的是初始值,
DOM property 返回的值是打印的
DOM property 不总是字符串。比如,input.checked 属性(用于复选框)是一个布尔:1
2
3
4
5
6<input id="input" type="checkbox" checked> checkbox
<script>
alert(input.getAttribute('checked')); // the attribute value is: empty string
alert(input.checked); // the property value is: true
</script>
还有其他例子:style
attribute 是一个字符串, 但是 style
property 却是一个对象:1
2
3
4
5
6<input id="input" type="checkbox" checked> checkbox
<script>
alert(input.getAttribute('checked')); // the attribute value is: empty string
alert(input.checked); // the property value is: true
</script>
这是一个重要的区别。 而且,即使 DOM property 类型是字符串,它可能与 attribute 不同!
例如,href DOM 属性总是一个完整的 URL,即使该属性包含一个相对的 URL 或者只是一个 # hash。1
2
3
4
5
6
7
8<a id="a" href="#hello">link</a>
<script>
// attribute
alert(a.getAttribute('href')); // #hello
// property
alert(a.href ); // full URL in the form http://site.com/page#hello
</script>
所以,如果我们需要 href 的值或者 HTML 中写的任何其他属性,我们可以使用 getAttribute。
非标准属性,dateset
在编写 HTML 时,我们使用了很多标准属性。 但是那些非标准的,定制的呢? 首先,让我们看看它们是否有用? 为什么?
有时非标准属性被用来传递从 HTML 到 JavaScript 的自定义数据,或者用于”标记”JavaScript 的 HTML-elements。
像这样:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<!-- 标记 这个 div 元素 用来展示 name 信息 -->
<div show-info="name"></div>
<!-- age -->
<div show-info="age"></div>
<script>
// 代码找到带有标记的元素,并显示所请求的内容
let user = {
name: "Pete",
age: 25
};
for(let div of document.querySelectorAll('[show-info]')) {
// 将相应的信息插入字段
let field = div.getAttribute('show-info');
div.innerHTML = user[field]; // Pete, then age
}
</script>
它们还可以用来设计元素。
例如,这里使用了 attribute order-state
的顺序状态:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26<style>
/* 样式依赖自定义 attribute "order-state" */
.order[order-state="new"] {
color: green;
}
.order[order-state="pending"] {
color: blue;
}
.order[order-state="canceled"] {
color: red;
}
</style>
<div class="order" order-state="new">
A new order.
</div>
<div class="order" order-state="pending">
A pending order.
</div>
<div class="order" order-state="canceled">
A canceled order.
</div>
为什么这个 attribute 可能比像这样的 class :.order-state-new
, .order-state-pending
, order-state-canceled
更好
这是因为一个属性更容易管理。 这种状态可以像以下那样容易改变:1
2
3// a bit simpler than removing old/adding a new class
// 比起 删除旧类/添加新类 要简单一点
div.setAttribute('order-state', 'canceled');
为了避免冲突,data-* 属性(attributes)诞生了。
所有以”date-“开头的属性(attributes)都保留给程序员使用。 它们可以在 dataset
属性(property)中使用。
例如,如果 elem
有一个名为 "data-about"
的属性,它可以作为 elem.dataset.about
使用。
像这样:1
2
3
4<body data-about="Elephants">
<script>
alert(document.body.dataset.about); // Elephants
</script>
Multiword attributes like data-order-state become camel-cased: dataset.orderState.
多个单词的 attributes 像是这样的 data-order-state
, 变成了驼峰写法:dataset.orderState
下面是一个重写的”订单状态”例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25<style>
.order[data-order-state="new"] {
color: green;
}
.order[data-order-state="pending"] {
color: blue;
}
.order[data-order-state="canceled"] {
color: red;
}
</style>
<div id="order" class="order" data-order-state="new">
A new order.
</div>
<script>
// read
alert(order.dataset.orderState); // new
// modify
order.dataset.orderState = "pending"; // (*)
</script>
使用 date-*
属性是传递自定义数据的有效、安全的方法。
总结
- Attribute 是在 HTML 中写的
- Properties 是 DOM 对象中的内容
使用 attributes 的方法有:
- elem.hasAttribute(name) 检测该 attribute 是否存在
- elem.getAttribute(name) 获取该 attribute 的值
- elem.setAttribute(name, value) 设置该 attribute 的值
- elem.removeAttribute(name) – 移除该 attribute
对于大多数需求,DOM property 可以很好地为我们服务。 我们只有在 DOM property 不适合我们的时候才会引用 attribute ,例如,当我们需要确切的 attribute 时,例如:
- 我们需要一个非标准属性。而且是以
date-
开头,我们使用dateset
- We want to read the value “as written” in HTML. The value of the DOM property may be different, for instance the href property is always a full URL, and we may want to get the “original” value.
- 我们想要在写在 HTML 中的值,但是通过 DOM property 获取的这个值和 HTML 中的不一样,例如:
href
属性(property) 总是一个完整的 url,而我们想要的是原始的值。
#日常使用
1 | <input id="search" value="foo" /> |
也就是说我们平时在写业务的时候多数情况下使用 property
是正确的。当用户在 input
元素输入更改的时候,attribute
特性的 value
属性的值不会变化,即使js更改 value
,也不会使 attribute
变化。
在javascript中我们推荐使用property属性因为这个属性相对attribute更快,更简便。尤其是有些类型本该是布尔类型的attribute特性。比如:”checked”, “disabled”, “selected”。浏览器会自动将这些值转变成布尔值传给property属性。
1 | <input id="test" class="blue" type="radio" /> |
好例子:1
2
3
4
5
6
7
8
9// get id
document.getElementById('test').id;
// set class
document.getElementById('test').className = 'red';
// get and set radio control status
document.getElementById('test').checked; // boolean
document.getElementById('test').checked = true;
$('#test').prop('checked'); // boolean
$('#test').prop('checked', true);
坏例子:1
2
3
4
5// get id
document.getElementById('test').getAttribute('id');
// set class
document.getElementById('test').setAttribute('class', 'red');
document.getElementById('test').getAttribute('checked'); // 返回字符串类型 'checked'
参考资料
输入框的value问题(DOM的property和attribute)
[译]HTML attribute与DOM property之间的区别?
JavaScript中的property和attribute的区别
Attributes and properties
DOM中Property与Attribute的区别
DOM系列:Attribute和Property